﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using IQReportes.Utils;
using System.Data;
using System.Data.SqlClient;
using System.Globalization;
using IQReportes.Models.Logica;

namespace IQReportes.Models
{
    public class LogicaPanelDeControl
    {
        private Dictionary<string, int> diccionarioDirsXLocal = new Dictionary<string, int>();
        private Dictionary<string, string> diccionarioLocalXCodigo = new Dictionary<string, string>();
        private Dictionary<string, List<string>> diccionarioLocalesXDistrito = new Dictionary<string, List<string>>();
        private Dictionary<string, string> diccionarioDistritos = new Dictionary<string, string>();
        private Dictionary<int, string> diccionarioMotivos = new Dictionary<int, string>();
        private Dictionary<int, string> diccionarioReps = new Dictionary<int, string>();
        private Dictionary<string, int> diccionarioDirsInactivosXLocal = new Dictionary<string, int>();

        private List<Ubigeo> listaUbigeo = new List<Ubigeo>(); //dato inicial
        private LogicaGeneral logicaGeneral = new LogicaGeneral();

        private DirDAO dbDirs = new DirDAO();
        private RepresentanteComercialDAO dbReps = new RepresentanteComercialDAO();
        private MotivoInoperativoDIRDAO dbMotivos = new MotivoInoperativoDIRDAO();
        private ConexionSQL dbSQL = new ConexionSQL();

        public LogicaPanelDeControl()
        {
            cargarDatosIniciales();
        }

        private void cargarDatosIniciales()
        {
            var motivos = dbMotivos.motivosInoperativos;
            foreach (var m in motivos)
            {
                diccionarioMotivos.Add(m.idMotivo, m.vcMotivo);
            }
            var reps = dbReps.representantes;
            foreach (var r in reps)
            {
                diccionarioReps.Add(r.idRepresentante, r.vcNombreCompleto);
            }

            //dirs inactivos
            DateTime fechaBase = (new LogicaParametro()).getFechaFinalPC();
            DateTime fechaAux = DateTime.ParseExact(fechaBase.ToString("dd/MM/yyyy"), "dd/MM/yyyy", CultureInfo.InvariantCulture);


            var dirsAct = dbDirs.dirs.Where(a => a.dtFechaUltimaTxn < fechaAux || a.dtFechaUltimaTxn == null).GroupBy(a => new
            {
                a.vcCodLocal
            }).Select(a => new
            {
                nombreLocal = a.Key.vcCodLocal,
                numDIRs = a.Select(x => x.vcCodDIR).Distinct().Count()
            });
            foreach (var e in dirsAct)
            {
                diccionarioDirsInactivosXLocal.Add(e.nombreLocal, e.numDIRs);
            }
        }

        //********************************************* INICIO CONSOLIDADO TREE *********************************************

        public List<TreeTransaccion> obtenerConsolidadoDirs(int codigoTabla, int institucion)
        {
            List<ConsolidadoGeneral> consolidado = new List<ConsolidadoGeneral>();
            List<TreeTransaccion> treeTransaccion = new List<TreeTransaccion>();
            List<TreeTransaccion> auxiliarTree = new List<TreeTransaccion>();
            treeTransaccion = armarTreeTransacciones(codigoTabla, institucion);

            return treeTransaccion;
        }

        private void cargarDiccionariosTree()
        {
            listaUbigeo = dbDirs.ubigeos.ToList();
            logicaGeneral.cargarDiccionariosTree(diccionarioDirsXLocal, diccionarioLocalXCodigo,
                                            diccionarioLocalesXDistrito, listaUbigeo, diccionarioDistritos);
        }


        public void obtenerDepartamentos(List<String> departamentos)
        {
            try
            {
                var dptos = listaUbigeo.AsEnumerable().GroupBy(a => a.vcDepartamento).Select(k => new { Departamento = k.Key }).ToList();
                for (int i = 0; i < dptos.Count(); i++)
                {
                    departamentos.Add(dptos[i].Departamento);
                }
            }
            catch (Exception e)
            {
                string gg = e.Message;
            }
        }


        public List<String> obtenerProvinciasXDepartamento(string nombreDepartamento, List<String> provincias)
        {
            List<String> retorno = new List<String>();
            retorno = logicaGeneral.obtenerProvinciasXDepartamento(nombreDepartamento, provincias, listaUbigeo);
                        
            return retorno;
            
        }

        public List<String> obtenerDistritosXProvincia(string departamento, string provincia, List<String> distritos)
        {
            List<String> retorno = new List<String>();
            retorno = logicaGeneral.obtenerDistritosXProvincia(departamento, provincia, distritos, listaUbigeo,
                                                               diccionarioDistritos);
            return retorno;
        }

        public List<String> obtenerLocalesXdistrito(List<String> listaLocales, string codDistrito)
        {
            List<String> retorno = new List<String>();
            retorno = logicaGeneral.obtenerLocalesXdistrito(listaLocales, codDistrito, diccionarioLocalesXDistrito,
                                                            diccionarioLocalXCodigo);

            return retorno;
        }

        private List<TreeTransaccion> armarTreeTransacciones(int codUnidadMedida, int institucion)
        {
            List<String> departamentos = new List<String>();//dato inicial
            List<TreeTransaccion> tree = new List<TreeTransaccion>();
            List<String> locales = new List<String>();
            List<String> auxDistritos = new List<String>();
            List<String> auxProvincias = new List<String>();
            List<String> auxDepartamentos = new List<String>();
            List<String> auxDistritos1 = new List<String>();
            List<String> auxProvincias1 = new List<String>();
            List<String> auxDepartamentos1 = new List<String>();
            List<String> auxLocales1 = new List<String>();
            string distritoactual;
            bool antes, despues;
            try
            {
                cargarDiccionariosTree();
                obtenerDepartamentos(departamentos);
                
                foreach (String d in departamentos)
                {
                    auxDepartamentos1.Add(d + " Dpto.");
                }

                foreach (String d in departamentos)
                {
                    auxProvincias1 = obtenerProvinciasXDepartamento(d, auxProvincias);
                    agregarHijosTree(d + " Dpto.", d, auxProvincias1, auxProvincias, tree, false);

                    foreach (String p in auxProvincias)
                    {
                        auxDistritos1 = obtenerDistritosXProvincia(d, p, auxDistritos);
                        agregarHijosTree(p + " Prov.", p, auxDistritos1, auxDistritos, tree, false);

                        foreach (String dist in auxDistritos)
                        {
                            distritoactual = dist;
                            auxLocales1 = obtenerLocalesXdistrito(locales, dist);
                            if (auxLocales1 != null && auxLocales1.Count() > 0)
                            {
                                antes = true;
                                agregarHijosTree(diccionarioDistritos[dist] + " Dist.", dist, auxLocales1, locales, tree, true);
                                despues = true;
                            }
                            locales = new List<String>();
                            antes = false;
                            despues = false;
                        }

                        auxDistritos = new List<String>();
                    }

                    auxProvincias = new List<String>();
                }
                //Agregar departamentos al tree

                agregarHijosTree("Peru", "Peru", auxDepartamentos1, departamentos, tree, false);
                TreeTransaccion elementoTree = new TreeTransaccion();
                elementoTree.vcHijo = "Peru";
                elementoTree.vcCodHijo = "Peru";
                elementoTree.vcPadre = null;
                elementoTree.vcCodPadre = null;
                tree.Add(elementoTree);
                return tree;
            }
            catch (Exception e)
            {
                string gg = e.Message;
                return null;
            }
        }

        public void gg()
        {
            DateTime fechaBase = (new LogicaParametro()).getFechaFinalPC();
            var dirsAct = dbDirs.dirs.Where(a=>a.dtFechaUltimaTxn < fechaBase).GroupBy(a=> new 
            {
                a.vcCodLocal
            }).Select(a => new
            {
                nombreLocal = a.Key.vcCodLocal,
                numDIRs = a.Select(x => x.vcCodDIR).Distinct().Count()
            });
            foreach(var e in dirsAct){
                diccionarioDirsInactivosXLocal.Add(e.nombreLocal, e.numDIRs);
            }
        }

        public void agregarHijosTree(String padre, string codPadre, List<String> hijos, List<string> codHijos, List<TreeTransaccion> tree, bool ultimoNivel)
        {
            TreeTransaccion elementoTree;
            int i ;
            int dirInactivos;
            try
            {
                for (i = 0; i < hijos.Count; i++)
                {
                    elementoTree = new TreeTransaccion();
                    elementoTree.vcHijo = hijos[i];
                    elementoTree.vcCodHijo = codHijos[i];
                    elementoTree.vcPadre = padre;
                    elementoTree.vcCodPadre = codPadre;
                    if (ultimoNivel)
                    {
                        
                        if (diccionarioDirsXLocal.ContainsKey(codHijos[i]))
                        {
                            elementoTree.inCantidadDIR = diccionarioDirsXLocal[codHijos[i]];//obtenerCantDirAleatorios();
                        }
                        //si es que no se encuentra el local dentro del diccionario de dirs x local entonces
                        //se asume q ese local tendrá 1 dir, solo ocurre para casos de prueba.
                        else { elementoTree.inCantidadDIR = 1; }

                        if (diccionarioDirsInactivosXLocal.ContainsKey(codHijos[i]))
                        {
                            dirInactivos = diccionarioDirsInactivosXLocal[codHijos[i]];
                        }
                        else
                        {
                            dirInactivos = 0;
                        }
                        elementoTree.inColor = (int)(((elementoTree.inCantidadDIR - dirInactivos) * Constantes.ESCALA_PORCENTAJE_TREE) / elementoTree.inCantidadDIR - Constantes.ESCALA_NEGATIVO_TREE);
                    }
                    tree.Add(elementoTree);
                }
            }
            catch (Exception e)
            {
                string gg = e.Message;
            }
        }
        //********************************************* FIN CONSOLIDADO TREE ***********************************************



        //********************************************** INICIO CONSOLIDADO ANTIGUEDAD ***************************************
        public List<ConsolidadoRazon> obtenerConsolidadoRazones(string elementoHijoNivel, string elementoPadreNivel, 
                                                                int nivel, int institucion, int? idTiempoSinTxn, int tipoChart)
        {
            
            List<ConsolidadoRazon> consolidadoRazones = new List<ConsolidadoRazon>();
            //modificar parametro de rango
            obtenerConsolidadoRazonesStoredProc(consolidadoRazones,elementoHijoNivel,elementoPadreNivel,nivel,institucion,
                                                idTiempoSinTxn, tipoChart);
            return consolidadoRazones;

        }

        private void obtenerConsolidadoRazonesStoredProc(List<ConsolidadoRazon> consolidadoRazones, string elementoHijoNivel,
                                                        string elementoPadreNivel,int nivel, int institucion,
                                                        int? idTiempoSinTxn,int tipoChart)
        {
            List<SqlParameter> listaParametros = new List<SqlParameter>();
            DataSet ds = new DataSet();

            DateTime fechaBase;
            DateTime? fechaParam;
            fechaParam = DateTime.Now;
            int leerFecha = 0;
            string stFecha = "";
            fechaBase = (new LogicaParametro()).getFechaFinalPC();

            if (idTiempoSinTxn != null)
            {
                var listaDias = (new LogicaAntiguedad()).getListDiasAntiguedad();
                var dia = listaDias.AsQueryable().Where(a => a.id == idTiempoSinTxn).First();
                
                if (dia.valor == -1)
                {
                    int maxDias = listaDias.AsQueryable().Max(a => a.valor);
                    stFecha = fechaBase.AddDays(-maxDias).ToString("yyyy-MM-dd");
                    leerFecha = 2;
                }
                else
                {
                    stFecha = fechaBase.AddDays(-dia.valor).ToString("yyyy-MM-dd");
                    leerFecha = 1;
                }
                //stFecha = DateTime.Now.AddDays(-4).ToString("yyyy-MM-dd");
                //stFecha = "2013-08-31";
                //fechaParam = DateTime.ParseExact(stFecha, "yyyy-MM-dd", CultureInfo.InvariantCulture);

            }
            else
            {
                stFecha = fechaBase.ToString("yyyy-MM-dd");
                leerFecha = 2;
            }

            agregarParametrosGenerales(listaParametros, elementoHijoNivel, elementoPadreNivel, nivel);
                        
            SqlParameter param3 = new SqlParameter("@codInstitucion", SqlDbType.Int);
            SqlParameter param4 = new SqlParameter("@fechaAntiguedad", SqlDbType.VarChar,50);
            SqlParameter param5 = new SqlParameter("@leerFecha", SqlDbType.Int);

            param3.Value = institucion;
            param4.Value = stFecha;
            param5.Value = leerFecha;
            
            listaParametros.Add(param3);
            listaParametros.Add(param4);
            listaParametros.Add(param5);
            if (tipoChart == Constantes.COLUMNCHART || tipoChart == Constantes.PIECHART)
            {
                dbSQL.ejecutarSelectProcedureDS(Utils.ProcedimientosAlmacenados.ConsolidadoRazones, listaParametros, ds);
            }
            else
            {
                dbSQL.ejecutarSelectProcedureDS(Utils.ProcedimientosAlmacenados.ConsolidadoRazonesLine, listaParametros, ds);
            }
            obtenerDataSetRazones(ds, consolidadoRazones,tipoChart);
        }

        private void obtenerDataSetRazones(DataSet ds, List<ConsolidadoRazon> consolidadoRazones, int tipoChart)
        {
            string idMotivo,stFecha;
            int cantDirs,i;
            ConsolidadoRazon elementoConsolidado;
            i = 0;
            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                elementoConsolidado = new ConsolidadoRazon();
                idMotivo = dr[i].ToString(); i++;
                if (tipoChart == Constantes.LINECHART || tipoChart == Constantes.TABLECHART)
                {
                    stFecha = dr[i].ToString(); i++;
                    elementoConsolidado.stFecha = (stFecha).Split(' ')[0];
                }
                if (idMotivo != null && idMotivo != "")
                {
                    elementoConsolidado.motivo = diccionarioMotivos[Int32.Parse(idMotivo)];
                    cantDirs = Int32.Parse(dr[i].ToString());
                    elementoConsolidado.cantidadDIRS = cantDirs;
                    consolidadoRazones.Add(elementoConsolidado);
                }
                i = 0;
                
            }
        }

        //********************************************** FIN CONSOLIDADO RAZONES *******************************************



        //********************************************** INICIO CONSOLIDADO ANTIGUEDAD ***************************************
        public List<ConsolidadoAntiguedad> obtenerConsolidadoAntiguedad(string elementoHijoNivel, string elementoPadreNivel, int nivel, 
                                                int institucion, int? idMotivo)
        {
            List<ConsolidadoAntiguedad> consolidadoAntiguedad = new List<ConsolidadoAntiguedad>();
            obtenerConsolidadoAntiguedadStoredProc(consolidadoAntiguedad, elementoHijoNivel, elementoPadreNivel, nivel, 
                                                institucion, idMotivo);
            return consolidadoAntiguedad;
        }


        private void obtenerConsolidadoAntiguedadStoredProc(List<ConsolidadoAntiguedad> consolidadoAntiguedad, string elementoHijoNivel, 
                                                            string elementoPadreNivel, int nivel, int institucion, int? idMotivo)
        {
            List<SqlParameter> listaParametros = new List<SqlParameter>();
            DataSet ds = new DataSet();
            agregarParametrosGenerales(listaParametros, elementoHijoNivel, elementoPadreNivel, nivel);

            SqlParameter param1 = new SqlParameter("@idMotivo", SqlDbType.Int);
            SqlParameter param2 = new SqlParameter("@codInstitucion", SqlDbType.Int);

            if (idMotivo != null)
            {
                param1.Value = idMotivo;
            }
            else
            {
                param1.Value = -1;
            }

            param2.Value = institucion;

            listaParametros.Add(param1);
            listaParametros.Add(param2);

            dbSQL.ejecutarSelectProcedureDS(Utils.ProcedimientosAlmacenados.ConsolidadoAntiguedad, listaParametros, ds);
            obtenerDataSetAntiguedad(ds, consolidadoAntiguedad);
        }

        private void obtenerDataSetAntiguedad(DataSet ds, List<ConsolidadoAntiguedad> consolidadoAntiguedad)
        {
            string stFecha;
            DateTime dtFecha, fechaBase;
            int numDirs;
            ConsolidadoAntiguedadAux elementoConsAux;
            List<ConsolidadoAntiguedadAux> listaConsolidadoAux = new List<ConsolidadoAntiguedadAux>();
            ConsolidadoAntiguedad elementoConsolidado;
            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                elementoConsAux = new ConsolidadoAntiguedadAux();

                stFecha = dr[0].ToString();
                if (stFecha != null && !Constantes.CADENA_VACIA.Equals(stFecha))
                {
                    stFecha = (stFecha).Split(' ')[0];
                    dtFecha = DateTime.ParseExact(stFecha, "dd/MM/yyyy", CultureInfo.InvariantCulture);
                }
                else
                {
                    dtFecha = DateTime.Now.AddDays(-15);
                }
                elementoConsAux.dtFechaUltimaTxn = dtFecha;
                numDirs = Int32.Parse(dr[1].ToString());
                elementoConsAux.cantDIRS = numDirs;
                listaConsolidadoAux.Add(elementoConsAux);
            }
            var listaDias = (new LogicaAntiguedad()).getListDiasAntiguedad(); //esto es la lista de los dias
                                                                            //que se van a mostrar en panel de control
            fechaBase = (new LogicaParametro()).getFechaFinalPC();
            TimeSpan intervalo;
            int cantDirs;
            int maxDias = listaDias.AsQueryable().Max(a=>a.valor);
            
            foreach(var dia in listaDias)
            {
                elementoConsolidado = new ConsolidadoAntiguedad();
                elementoConsolidado.numeroDIRS = 0;
                elementoConsolidado.diasAntiguedad = dia.valor;
                elementoConsolidado.nombreDiasAnt = dia.nombre;


                if (dia.valor == -1)
                {
                    DateTime fechaAux = DateTime.ParseExact(fechaBase.AddDays(-maxDias).ToString("dd/MM/yyyy"), "dd/MM/yyyy", CultureInfo.InvariantCulture);

                    cantDirs = listaConsolidadoAux.AsQueryable().Where(a => a.dtFechaUltimaTxn < fechaAux).Sum(a => a.cantDIRS);
                    elementoConsolidado.numeroDIRS = cantDirs;

                }
                else
                {
                    foreach (var c in listaConsolidadoAux)
                    {
                        //si la dif de dias es igual a lista entonces agregar
                        intervalo = fechaBase.Subtract(c.dtFechaUltimaTxn);

                        if (dia.valor == intervalo.Days)
                        {
                            elementoConsolidado.numeroDIRS = c.cantDIRS;
                        }
                    }
                }
                consolidadoAntiguedad.Add(elementoConsolidado);
            }
            
        }
        //********************************************** FIN CONSOLIDADO ANTIGUEDAD ***************************************



        //********************************************** INICIO REPRESENTANTES COM. ***************************************
        public List<DIR> obtenerRepComerciales(string elementoHijoNivel, string elementoPadreNivel, 
                                        int nivel, int institucion, int? idMotivo, int? idTiempoSinTxn)
        {
            List<DIR> consolidadoDIR = new List<DIR>();
            obtenerRepComercialStoredProc(consolidadoDIR, elementoHijoNivel, elementoPadreNivel,
                                         nivel, institucion, idMotivo, idTiempoSinTxn);
            return consolidadoDIR;
        }

        private void obtenerRepComercialStoredProc(List<DIR> consolidadoDIRs, 
                                                    string elementoHijoNivel, string elementoPadreNivel, 
                                                    int nivel, int institucion, int? idMotivo,int? idTiempoSinTxn)
        {
            //OJO REVISARR!!!
            List<SqlParameter> listaParametros = new List<SqlParameter>();
            DataSet ds = new DataSet();

            DateTime fechaBase;
            fechaBase = (new LogicaParametro()).getFechaFinalPC();
            int leerFecha = 0;
            string stFecha = "";
            if (idTiempoSinTxn != null)
            {
                var listaDias = (new LogicaAntiguedad()).getListDiasAntiguedad();
                var dia = listaDias.AsQueryable().Where(a => a.id == idTiempoSinTxn).First();
                fechaBase = (new LogicaParametro()).getFechaFinalPC();
                if (dia.valor == -1)
                {
                    int maxDias = listaDias.AsQueryable().Max(a => a.valor);
                    stFecha = fechaBase.AddDays(-maxDias).ToString("yyyy-MM-dd");
                    leerFecha = 2;
                }
                else
                {
                    stFecha = fechaBase.AddDays(-dia.valor).ToString("yyyy-MM-dd");
                    leerFecha = 1;
                }
            }
            else
            {
                stFecha = fechaBase.ToString("yyyy-MM-dd");
                leerFecha = 2;
            }
            agregarParametrosGenerales(listaParametros, elementoHijoNivel, elementoPadreNivel, nivel);

            SqlParameter param1 = new SqlParameter("@idMotivo", SqlDbType.Int);
            SqlParameter param2 = new SqlParameter("@codInstitucion", SqlDbType.Int);
            SqlParameter param4 = new SqlParameter("@fechaAntiguedad", SqlDbType.VarChar, 50);
            SqlParameter param5 = new SqlParameter("@leerFecha", SqlDbType.Int);

            if (idMotivo != null)
            {
                param1.Value = idMotivo;
            }
            else
            {
                param1.Value = -1;
            }

            param2.Value = institucion;
            param4.Value = stFecha;
            param5.Value = leerFecha;

            listaParametros.Add(param1);
            listaParametros.Add(param2);
            listaParametros.Add(param4);
            listaParametros.Add(param5);

            dbSQL.ejecutarSelectProcedureDS(Utils.ProcedimientosAlmacenados.ConsolidadoRepresentantes, listaParametros, ds);
            obtenerDataSetRepresentantes(ds, consolidadoDIRs);
        }

        private void obtenerDataSetRepresentantes(DataSet ds, List<DIR> consolidadoDIRs)
        {
            DIR elementoConsAux;
            int idrep;
            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                elementoConsAux = new DIR();
                elementoConsAux.vcCodDIR = dr[0].ToString();
                if (dr[1].ToString() == null || dr[1].ToString() == "")
                {
                    elementoConsAux.vcNombreRepresentante = "Sin Representante";
                }
                else
                {
                    idrep = Int32.Parse(dr[1].ToString());
                    elementoConsAux.idRepresentante = idrep;
                    elementoConsAux.vcNombreRepresentante = diccionarioReps[idrep];
                }
                if (dr[2].ToString() == null || dr[2].ToString() == "")
                {
                    elementoConsAux.vcCodTienda = "Sin Código";
                }
                else
                {
                    elementoConsAux.vcCodTienda = dr[2].ToString();
                }


                if (dr[2].ToString() == null || dr[3].ToString() == "")
                {
                    elementoConsAux.vcNombreTienda = "Sin Nombre";
                }
                else
                {
                    elementoConsAux.vcNombreTienda = dr[3].ToString();
                }
                consolidadoDIRs.Add(elementoConsAux);
            }
        }
        //********************************************** FIN REPRESENTANTES COM. ******************************************



        public void agregarParametrosGenerales(List<SqlParameter> listaParametros, string elementoHijoNivel,
                                        string elementoPadreNivel, int nivel)
        {
            
            SqlParameter param2 = new SqlParameter("@elementoHijo", SqlDbType.VarChar, 100);
            SqlParameter param3 = new SqlParameter("@elementoPadre", SqlDbType.VarChar, 100);
            SqlParameter param5 = new SqlParameter("@nivel", SqlDbType.Int);
                        
            param5.Value = nivel;

            if (elementoHijoNivel == null || Constantes.CADENA_VACIA.Equals(elementoHijoNivel))
            {
                param2.Value = Constantes.CADENA_VACIA;
            }
            else
            {
                param2.Value = elementoHijoNivel;
            }
            if (elementoPadreNivel == null || Constantes.CADENA_VACIA.Equals(elementoPadreNivel))
            {
                param3.Value = Constantes.CADENA_VACIA;
            }
            else
            {
                param3.Value = elementoPadreNivel;
            }

            listaParametros.Add(param2);
            listaParametros.Add(param3);
            listaParametros.Add(param5);
        }
    }
}